package service

import (
	"context"
	"database/sql"
	"encoding/json"
	"fx_swift_ifcgate/api"
	"fx_swift_ifcgate/internal/model"
	"fx_swift_ifcgate/pkg/code"
	"fx_swift_ifcgate/pkg/global"
	"fx_swift_ifcgate/pkg/internalerrors"
	"fx_swift_ifcgate/pkg/logger"
	"fx_swift_ifcgate/pkg/utils"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/jinzhu/copier"
	"strings"
)

type IVAInfoSrv interface {
	CreateVAInfo(ctx context.Context, req *api.VaInfoReq) error
	QueryApplyCode(ctx context.Context, parentCode string) ([]*api.ApplyCodeRes, error)
	QueryVAInfoCallBackList(ctx context.Context) ([]*api.VAInfoListRes, error)
	QueryCurrencyCode(ctx context.Context, req *api.CurrencyReq) ([]*api.CurrencyRes, error)
	QueryVAInfo(ctx context.Context, merOrderNo string) ([]*api.VaInfoRes, error)
	GetTradeCodeType(ctx context.Context) ([]*api.TradeCodeTypeRes, error)
}

type vaInfoSrv struct {
}

func NewVAInfoSrv() IVAInfoSrv {
	return &vaInfoSrv{}
}

// 获取交易编码
func (v vaInfoSrv) GetTradeCodeType(ctx context.Context) ([]*api.TradeCodeTypeRes, error) {
	var (
		err              error
		tradeCodeTypeObj []*model.IFCGateTradeCodeType
	)
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_trade_code_type_base").Scan(&tradeCodeTypeObj); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	if tradeCodeTypeObj == nil {
		return []*api.TradeCodeTypeRes{}, nil
	}

	result := make([]*api.TradeCodeTypeRes, 0)
	for _, value := range tradeCodeTypeObj {
		result = append(result, &api.TradeCodeTypeRes{
			Code: value.Code,
			Desc: value.Desc,
		})
		global.TradeCodeMap[value.Code] = value.Desc
	}
	return result, err
}

// 获取va开户资料
func (v vaInfoSrv) QueryVAInfo(ctx context.Context, merOrderNo string) ([]*api.VaInfoRes, error) {
	var (
		err       error
		vaInfoObj []*model.IFCGateVaInfo
		//merChantNo string
	)

	//merChantNo = ctx.Value("MerchantNo").(string)
	if err = global.GFDB.Model("ifcgate_va_info").Where("mer_order_no=?", merOrderNo).Scan(&vaInfoObj); err != nil {
		logger.SugarLogger.Error(err)
		return []*api.VaInfoRes{}, nil
	}
	if vaInfoObj == nil {
		return []*api.VaInfoRes{}, internalerrors.New(code.ErrUnknown, "暂无查询数据")
	}

	result := make([]*api.VaInfoRes, 0)
	for _, value := range vaInfoObj {
		busDesDocumentSplit := []string{}
		storeHoldCertify := []string{}
		if value.BusDesDocument != "" {
			busDesDocumentSplit = strings.Split(value.BusDesDocument, ";")
		}
		if value.StoreHoldCertify != "" {
			storeHoldCertify = strings.Split(value.StoreHoldCertify, ";")
		}
		result = append(result, &api.VaInfoRes{
			MerOrderNo:       value.MerOrderNo,
			BizFlow:          value.BizFlow,
			ParentCode:       value.ParentCode,
			ApplyCode:        value.ApplyCode,
			Currency:         value.Currency,
			Area:             value.Area,
			AcctSimpleName:   value.AcctSimpleName,
			BankType:         value.BankType,
			ShopName:         value.ShopName,
			ShopUrl:          value.ShopUrl,
			CollectType:      value.CollectType,
			CollectName:      value.CollectName,
			WebSiteUrl:       value.WebSiteUrl,
			IsSameName:       value.IsSameName,
			CallBackUrl:      value.CallBackUrl,
			BusDesDocument:   busDesDocumentSplit,
			StoreHoldCertify: storeHoldCertify,
			OtherPath:        value.OtherPath,
			Postscript:       value.Postscript,
			Status:           value.Status,
		})
	}
	return result, err
}

// 获取币种
func (v vaInfoSrv) QueryCurrencyCode(ctx context.Context, req *api.CurrencyReq) ([]*api.CurrencyRes, error) {
	var (
		err            error
		vaConditionObj []*model.IFCGateVACondition
	)
	if req.ParentCode == "" {
		return []*api.CurrencyRes{}, internalerrors.New(code.ErrUnknown, "传统外贸不能为空")
	}
	if req.ApplyDesc == "" {
		return []*api.CurrencyRes{}, internalerrors.New(code.ErrUnknown, "贸易类目不能为空")
	}
	if req.IsoCountryCode == "" {
		return []*api.CurrencyRes{}, internalerrors.New(code.ErrUnknown, "收款国家/地区不能为空")
	}

	if err = global.GFDB.Ctx(ctx).Model("ifcgate_va_condition_base").Where("parent_code=? and apply_desc_en=? and (iso_country_code=? or iso_country_code='ALL') and bank_code is not null", req.ParentCode, req.ApplyDesc, req.IsoCountryCode).
		Scan(&vaConditionObj); err != nil {
		logger.SugarLogger.Error(err)
		return []*api.CurrencyRes{}, internalerrors.New(code.ErrUnknown, "查询数据报错")
	}
	if vaConditionObj == nil {
		return []*api.CurrencyRes{}, nil
	}

	result := make([]*api.CurrencyRes, 0)
	for _, value := range vaConditionObj {
		result = append(result, &api.CurrencyRes{
			Id:           value.Id,
			BankType:     value.BankCode,
			CurrencyCode: value.CurrencyCode,
			IsSameName:   value.IsSameName,
			Bank:         value.Bank,
			PayType:      value.PayType,
		})
	}
	return result, err
}

// 查询VA账户详情
func (v vaInfoSrv) QueryVAInfoCallBackList(ctx context.Context) ([]*api.VAInfoListRes, error) {
	var (
		err           error
		vaInfoListObj []*model.IFCGateVAInfoCallBack
		merChantNo    string
	)

	merChantNo = ctx.Value("MerchantNo").(string)
	if err = global.GFDB.Model("ifcgate_vainfo_call_back").Where("merchant_no=?", merChantNo).OrderDesc("created_at").Scan(&vaInfoListObj); err != nil {
		logger.SugarLogger.Error(err)
		return []*api.VAInfoListRes{}, nil
	}
	if vaInfoListObj == nil {
		return []*api.VAInfoListRes{}, nil
	}

	vaInfoListObj = SortByStatus(vaInfoListObj)
	result := make([]*api.VAInfoListRes, 0)
	for _, value := range vaInfoListObj {
		result = append(result, &api.VAInfoListRes{
			MerOrderNo:  value.MerOrderNo,
			BizFlow:     value.BizFlow,
			CodeName:    value.CodeName,
			BankCode:    value.BankCode,
			Currency:    value.Currency,
			AccountName: value.AccountName,
			AccountNo:   value.AccountNo,
			BankName:    value.BankName,
			BankAddress: value.BankAddress,
			BranchCode:  value.BranchCode,
			CreatedAt:   value.CreatedAt,
			Area:        value.Area,
			CodeValue:   value.CodeValue,
			Remark:      value.Remark,
			Status:      value.Status,
		})
	}
	return result, err
}

// 获取申请子类
func (v vaInfoSrv) QueryApplyCode(ctx context.Context, parentCode string) ([]*api.ApplyCodeRes, error) {
	var (
		err          error
		applyCodeObj []*model.ApplyCode
	)

	if parentCode == "" {
		return []*api.ApplyCodeRes{}, internalerrors.New(code.ErrUnknown, "申请大类不能为空")
	}

	if err = global.GFDB.Ctx(ctx).Model("ifcgate_apply_code_base").Where("code", parentCode).Scan(&applyCodeObj); err != nil {
		logger.SugarLogger.Error(err)
		return []*api.ApplyCodeRes{}, internalerrors.New(code.ErrUnknown, "查询数据报错")
	}
	if applyCodeObj == nil {
		return []*api.ApplyCodeRes{}, nil
	}

	result := make([]*api.ApplyCodeRes, 0)
	for _, value := range applyCodeObj {
		result = append(result, &api.ApplyCodeRes{
			ParentCode: value.Code,
			DescEn:     value.DescEn,
			DescZh:     value.DescZh,
		})
	}
	return result, err
}

// VA开户申请
func (v vaInfoSrv) CreateVAInfo(ctx context.Context, req *api.VaInfoReq) error {
	var (
		err           error
		resStr        []byte
		vaInfoObj     *model.IFCGateVaInfo
		result        sql.Result
		rowsNums      int64
		merchantToken string
		merChantNo    string
		oldMerOrderNo string
		nums          int
	)

	merChantNo = ctx.Value("MerchantNo").(string)

	//根据订单号判断是新增/修改
	if req.MerOrderNo != "" {
		oldMerOrderNo = req.MerOrderNo
	} else {
		nums, err = global.GFDB.Model("ifcgate_va_info").Where("merchant_no=?", merChantNo).Count()
		if err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, "数据查询异常")
		}
		if nums >= 4 {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, "最多只能添加4个账户")
		}
	}
	//if len(req.AcctSimpleName) > 128 {
	//	return internalerrors.New(code.ErrUnknown, "账户简称长度不能超过128")
	//}
	//if len(req.ShopName) > 128 {
	//	return internalerrors.New(code.ErrUnknown, "店铺名称长度不能超过128")
	//}
	//if len(req.ShopUrl) > 350 {
	//	return internalerrors.New(code.ErrUnknown, "店铺链接长度不能超过350")
	//}
	req.MerOrderNo = utils.GenerateCode64()
	req.CallBackUrl = global.ViperObj.GetString("callback.vaCallBackUrl")
	req.Postscript = global.ViperObj.GetString("vainfo.postscript")
	merchantToken, err = GetMerchantToToken(ctx)
	if merchantToken == "" || err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}

	//将文件地址替换成sftp地址
	converReq := &api.VaInfoReq{}
	copier.Copy(&converReq, &req)
	tarGetPath := global.ViperObj.GetString("sftp.targetPath")
	if len(converReq.BusDesDocument) != 0 {
		filePath := converReq.BusDesDocument[0]
		busDesDocumentStr := strings.Join(converReq.BusDesDocument, ";")
		lastPath := strings.LastIndex(filePath, "/")
		subStr := filePath[:lastPath]
		busDesDocumentStr = strings.ReplaceAll(busDesDocumentStr, subStr, tarGetPath)
		converReq.BusDesDocument = strings.Split(busDesDocumentStr, ";")
	}
	if len(converReq.StoreHoldCertify) != 0 {
		filePath := converReq.StoreHoldCertify[0]
		storeHoldCertifyStr := strings.Join(converReq.StoreHoldCertify, ";")
		lastPath := strings.LastIndex(filePath, "/")
		subStr := filePath[:lastPath]
		storeHoldCertifyStr = strings.ReplaceAll(storeHoldCertifyStr, subStr, tarGetPath)
		converReq.StoreHoldCertify = strings.Split(storeHoldCertifyStr, ";")
	}
	if converReq.OtherPath != "" {
		filePath := converReq.OtherPath
		lastPath := strings.LastIndex(filePath, "/")
		subStr := filePath[:lastPath]
		filePath = strings.ReplaceAll(filePath, subStr, tarGetPath)
		converReq.OtherPath = filePath
	}

	body, _ := json.Marshal(converReq)
	resStr, err = OperatorParamToPost("tp1017", merchantToken, body)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	//返回结果集解析
	resObj := &api.VAInfoRes{}
	err = json.Unmarshal(resStr, &resObj)
	if err != nil {
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if resObj.VAInfoHead.RespCode == "S00000" && resObj.VAInfoHead.RespDesc == "请求成功" {
		db := g.DB()
		err = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
			vaInfoList := []*model.IFCGateVaInfo{}
			vaInfoObj = &model.IFCGateVaInfo{}
			vaInfoObj.MerOrderNo = req.MerOrderNo
			vaInfoObj.MerChantNo = merChantNo
			vaInfoObj.ParentCode = req.ParentCode
			vaInfoObj.ApplyCode = req.ApplyCode
			vaInfoObj.Area = req.Area
			vaInfoObj.Currency = req.Currency
			vaInfoObj.AcctSimpleName = req.AcctSimpleName
			vaInfoObj.BankType = req.BankType
			vaInfoObj.ShopName = req.ShopName
			vaInfoObj.ShopUrl = req.ShopUrl
			vaInfoObj.CollectType = req.CollectType
			vaInfoObj.CollectName = req.CollectName
			vaInfoObj.WebSiteUrl = req.WebSiteUrl
			vaInfoObj.IsSameName = req.IsSameName
			vaInfoObj.BusDesDocument = strings.Join(req.BusDesDocument, ";")
			vaInfoObj.StoreHoldCertify = strings.Join(req.StoreHoldCertify, ";")
			vaInfoObj.CallBackUrl = global.ViperObj.GetString("callback.vaCallBackUrl")
			vaInfoObj.OtherPath = req.OtherPath
			vaInfoObj.Postscript = req.Postscript
			vaInfoObj.BizFlow = resObj.VAInfoBody.BizFlow
			vaInfoObj.Status = resObj.VAInfoBody.Status
			vaInfoList = append(vaInfoList, vaInfoObj)

			//先删除
			result, err = global.GFDB.Model("ifcgate_va_info").Where("mer_order_no=?", oldMerOrderNo).Delete()
			if err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
			//后插入
			result, err = tx.Model("ifcgate_va_info").Data(vaInfoList).Insert()
			if err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
			rowsNums, err = result.RowsAffected()
			if err != nil || rowsNums == 0 {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}

			vaInfoCallBackList := []*model.IFCGateVAInfoCallBack{}
			vaInfoCallBackObj := &model.IFCGateVAInfoCallBack{}
			vaInfoCallBackObj.MerOrderNo = req.MerOrderNo
			vaInfoCallBackObj.MerChantNo = merChantNo
			vaInfoCallBackObj.Status = "OPENING"
			vaInfoCallBackObj.BizFlow = resObj.VAInfoBody.BizFlow
			vaInfoCallBackList = append(vaInfoCallBackList, vaInfoCallBackObj)

			//先删除
			result, err = global.GFDB.Model("ifcgate_vainfo_call_back").Where("mer_order_no=?", oldMerOrderNo).Delete()
			if err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, "va入户数据删除失败")
			}
			//后插入
			result, err = tx.Model("ifcgate_vainfo_call_back").Data(vaInfoCallBackList).Insert()
			if err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, "va入户数据写入失败")
			}
			rowsNums, err = result.RowsAffected()
			if err != nil || rowsNums == 0 {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, "va入户数据写入失败")
			}
			return nil
		})

		if err != nil {
			logger.SugarLogger.Error("VA开户事务执行出错", err)
		} else {
			logger.SugarLogger.Info("VA开户事务执行成功")
		}
	}
	return nil
}
